package org.mixed.core.resource;

import org.mixed.core.enums.JsonCodeConstants;
import org.mixed.core.utils.IoUtils;
import org.mixed.core.utils.JsonUtils;
import org.mixed.core.utils.PathUtils;
import org.mixed.service.MixResourceService;

import java.nio.charset.StandardCharsets;

public interface ResourceStorage<T extends Info> extends JsonCodeConstants {
    String separatorWithCRLF = "\r\n================================\r\n";
    String separatorWithLF = "\n================================\n";
    String folder();
    String suffix();
    Class<T> infoClass();
    default boolean requirePath() {
        return true;
    }
    default boolean requiredScript() {
        return true;
    }
    default boolean allowRoot() {
        return false;
    }

    default String buildKey(Info info) {
        String groupPath = getResourceService().getGroupPath(info.getGroupId());
        return PathUtils.replaceSlash("/" + groupPath + "/" + info.getPath());
    }

    void setResourceService(MixResourceService resourceService);
    MixResourceService getResourceService();

    default T readResource(Resource resource) {
        return read(resource.read());
    }

    default T read(byte[] bytes) {
        String content = new String(bytes, StandardCharsets.UTF_8);
        if (requiredScript()) {
            String separator = separatorWithCRLF;
            int index = content.indexOf(separator);
            if (index == -1) {
                separator = separatorWithLF;
                index = content.indexOf(separatorWithLF);
            }
            if (index > -1) {
                T info = JsonUtils.readValue(content.substring(0, index), infoClass());
                info.setScript(content.substring(index + separator.length()));
                return info;
            }
        }
        return JsonUtils.readValue(content, infoClass());
    }

    default byte[] write(Info info) {
        String script = info.getScript();
        info.setScript(null);
        return (JsonUtils.toJsonString(info) + separatorWithCRLF + script).getBytes(StandardCharsets.UTF_8);
    }

    default void validate(T info) {
        notNull(info.getGroupId(), GROUP_ID_REQUIRED);
        notBlank(info.getName(), NAME_REQUIRED);
        isTrue(IoUtils.validateFileName(info.getName()), NAME_INVALID);
        if (requiredScript()) {
            notBlank(info.getScript(), SCRIPT_REQUIRED);
        }
        if (requirePath()) {
            notBlank(info.getPath(), PATH_REQUIRED);
            isTrue(getResourceService().pathNotMatch(folder(), buildKey(info), info.getId()), PATH_CONFLICT);
        }
    }
}
